package com.ourcraft.informationcollectionsystem.utils;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Date;
import java.util.List;

public class ExportAndSendExcel {
    public Workbook workbook;
    public Sheet sheet;
    public Class<?> aClass;

    public ExportAndSendExcel(Class<?> aClass){
        this.aClass = aClass;
        this.workbook = new XSSFWorkbook();
    }

    public Workbook export(List<?> dataList){
        setHeader(); // 添加表头
        try {
            fillRow(dataList); // 添加行
        }
        catch (IllegalAccessException | InvocationTargetException ignored) {}

        return workbook;
    }

    public static File save(Workbook workbook){
        String randomFileName = RandomStringUtils.randomAlphanumeric(32);
        File targetDir = new File("./excels/" + randomFileName + ".xlsx");

        try {
            FileOutputStream outputStream = new FileOutputStream(targetDir);
            workbook.write(outputStream);
            workbook.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return targetDir;
    }

    public ResponseEntity<Resource> send(){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            workbook.write(baos);
        } catch (IOException e) { }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType("application", "force-download"));
        headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; ");

        var bytes = baos.toByteArray();
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(bytes.length)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(new ByteArrayResource(bytes));

    }

    private void setHeader(){
        // 使用反射机制，自动读取Entity中的字段，使得修改数据库仅需修改对应Entity、需要导出新table时直接使用，不需要修改本类
        Method[] methods = aClass.getMethods();
        this.sheet = workbook.createSheet(ColumnNameCN.map_table.get(aClass.getName()));

        var header = sheet.createRow(0);
        int j = 0;
        for(var method :methods){
            var column_Chinese_name = columnName(method); // 从table的英文列名获取对应的中文名；如果不存在返回null
            if (column_Chinese_name == null)
                continue;

            Cell headerCell = header.createCell(j);
            headerCell.setCellValue(column_Chinese_name);
            ++j;
        }
    }

    private void fillRow(List<?> dataList) throws InvocationTargetException, IllegalAccessException {
        for(int i = 0; i < dataList.size(); ++i){
            Object data = dataList.get(i);
            var row = sheet.createRow(i + 1);

            // 都是method，顺序一定和表头匹配
            Method[] methods = aClass.getMethods();
            int j = 0;
            for (var method :methods){
                var column_Chinese_name = columnName(method);
                if (column_Chinese_name == null)
                    continue;

                var result = method.invoke(data);
                var returnType = method.getReturnType();

                Cell cell = row.createCell(j++);
                // 根据类的类型赋值cell，Java不允许绕过类型判断
                if (result == null){ }
                else if (returnType.equals(Integer.class)) {
                    cell.setCellValue((Integer) result);
                } else if (returnType.equals(Date.class)) {
                    cell.setCellValue((Date) result);
                } else if (returnType.equals(String.class)) {
                    cell.setCellValue((String) result);
                }
            }
        }
    }

    private String columnName(Method method){
        var method_name = method.getName();
        // setVariableName -> variableName
        var variable_name = (char)(method_name.charAt(3) | 0x20) + method_name.substring(4);
        var column_Chinese_name = ColumnNameCN.getColumnChineseName(variable_name);

        return !method_name.startsWith("get") ? null : column_Chinese_name;
    }
}
